package org.jvending.provisioning.stocking.handler;

import org.hibernate.Hibernate;
import org.jvending.provisioning.config.MimeTypeRepository;
import org.jvending.provisioning.descriptor.media.MediaObjectType;
import org.jvending.provisioning.descriptor.media.MediaType;
import org.jvending.provisioning.descriptor.media.ObjectURIType;
import org.jvending.provisioning.descriptor.media.ProductType;
import org.jvending.provisioning.model.clientbundle.ContentFile;
import org.jvending.provisioning.stocking.StockingException;
import org.jvending.provisioning.stocking.par.DescriptorFileType;
import org.jvending.registry.RepositoryRegistry;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.io.ByteArrayInputStream;
import java.sql.Blob;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

public class OtaHandler implements DescriptorHandler {

    private static Logger logger = Logger.getLogger("OtaHandler");

    /**
     * RepositoryRegisty instance
     */
    private RepositoryRegistry repositoryRegistry;

    public void setRepositoryRegistry(RepositoryRegistry repositoryRegistry) {
        if (repositoryRegistry == null) {
            throw new IllegalArgumentException("repositoryRegistry");
        }
        this.repositoryRegistry = repositoryRegistry;
    }

    public List<ContentFile> getContentFiles(DescriptorFileType descriptorFileType, Map contentMap) throws StockingException {
        if (descriptorFileType == null) {
            throw new IllegalArgumentException("descriptorFileType");
        }
        if (contentMap == null) {
            throw new IllegalArgumentException("contentMap");
        }

        logger.info("Starting Ota Handler");
        List<ContentFile> contents = new ArrayList<ContentFile>();
        String uri = descriptorFileType.getValue();
        if (uri == null || isRemoteUri(uri.trim())) {
            logger.info("JV-1800-002: Remote or null URI. Not processing content: URI = " + uri);
            return contents;
        }
        String mimeType = descriptorFileType.getMimeType();
        MimeTypeRepository mimeRepo = (MimeTypeRepository) repositoryRegistry.find("mimetype");
        if (mimeType == null) mimeType = mimeRepo.getMimeTypeFromUri(descriptorFileType.getValue());

        if (mimeType == null) {
            logger.info("JV-1800-003: Cannot determine the mime-type of this descriptor: URI = " + uri);
            return contents;
        }

        if (!mimeType.equals("application/vnd.oma.dd2+xml")) {
            logger.info("JV-1800-004: Not OTA Descriptor mime-type: URI = " + uri + ", mimeType = " + mimeType);
            return contents;
        }

        byte[] descriptorBytes = (byte[]) contentMap.get(uri.trim());
        if (descriptorBytes == null) {
            logger.info("JV-1800-005: Cannot find local copy of this descriptor: URI = " + uri + ", Content Keys = "
                    + contentMap.keySet());
            return contents;
        }
        MediaType mediaType;
        try {
            JAXBContext jaxbContext = JAXBContext.newInstance("org.jvending.provisioning.descriptor.media");
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
            unmarshaller.setValidating(true);
            mediaType = (MediaType) unmarshaller.unmarshal(new ByteArrayInputStream(descriptorBytes));
        } catch (JAXBException e) {
            throw new StockingException("JV-101-002: Critical - Problem with Schema! " + new String(descriptorBytes), e);
        }
        for (ProductType productType : (List<ProductType>) mediaType.getProduct()) {

            for (MediaObjectType mediaObjectType : (List<MediaObjectType>) productType.getMediaObject()) {
                ObjectURIType objectURIType = mediaObjectType.getObjectURI();

                List<String> serverURIs = (List<String>) objectURIType.getServer();
                String serverURI = serverURIs.get(0);

                ContentFile assemblyFile = createContentFileFor(serverURI,
                        (String) mediaObjectType.getType().get(0), contentMap);
                if (assemblyFile != null) contents.add(assemblyFile);
            }
        }
        return contents;
    }

    private static ContentFile createContentFileFor(String uri, String mimeType, Map contentMap) {
        byte[] assemblyFile = (byte[]) contentMap.get(uri.trim());
        if (assemblyFile == null) {
            logger.info("JV-1800-007: Could not find local copy of assembly: URI = " + uri + ", Content Keys = "
                    + contentMap.keySet());
            return null;
        }
        ByteArrayInputStream is = new ByteArrayInputStream(assemblyFile);
        Blob contentBlob = Hibernate.createBlob(is, assemblyFile.length);
        ContentFile contentFile = new ContentFile();
        contentFile.setContent(contentBlob);
        contentFile.setFileUri(uri);
        contentFile.setMimeType(mimeType);
        contentFile.setBytes(assemblyFile);
        return contentFile;
    }

    private static boolean isRemoteUri(String uri) {
        return (uri != null && (uri.startsWith("http://") || uri.startsWith("ftp://") || uri.startsWith("https://")));
    }
}
